When working with encapsulation, you must always take into account which aspects of a type are visible to various parts of your application. Specifically, types (classes, interfaces, structures, enumerations, and delegates) as well as their members (properties, methods, constructors, and fields) are defined using a specific keyword to control how "visible" the item is to other parts of your application. Although C# defines numerous keywords to control access, they differ on where they can be successfully applied (type or member). Table 5-1 documents the role of each access modifier and where it may be applied.
Table 5-1. C# Access Modifiers
C# Access Modifier | May Be Applied To | Meaning In Life |
---|---|---|
public | Types or type members | Public items have no access restrictions. A public member can be accessed from an object as well as any derived class. A public type can be accessed from other external assemblies. |
private | Type members or nested types | Private items can only be accessed by the class (or structure) that defines the item. |
protected | Type members or nested types | Protected items can be used by the class which defines it, and any child class. However, protected items cannot be accessed from the outside world using the C# dot operator. |
internal | Types or type members | Internal items are accessible only within the current assembly. Therefore, if you define a set of internal types within a .NET class library, other assemblies are not able to make use of them. |
protected internal | Type members or nested types | When the protected and internal keywords are combined on an item, the item is accessible within the defining assembly, the defining class, and by derived classes. |
In this chapter, you are only concerned with the public and private keywords. Later chapters will examine the role of the internal and protected internal modifiers (useful when you build .NET code libraries) and the protected modifier (useful when you are creating class hierarchies).
By default, type members are implicitly private while types are implicitly internal. Thus, the following class definition is automatically set to internal, while the type's default constructor is automatically set to private:
// An internal class with a private default constructor. class Radio { Radio(){} }
To allow other parts of a program to invoke members of an object, you must mark them as publicly accessible. As well, if you wish to expose the Radio to external assemblies (useful when building .NET code libraries) you will need to add the public modifier.
// A public class with a public default constructor. public class Radio { public Radio(){} }
As mentioned in Table 5-1, the private, protected, and protected internal access modifiers can be applied to a nested type. What you need to know at this point, however, is that a nested type is a type declared directly within the scope of class or structure. By way of example, here is a private enumeration (named Color) nested within a public class (named SportsCar):
public class SportsCar { // OK! Nested types can be marked private. private enum CarColor { Red, Green, Blue } }
Here, it is permissible to apply the private access modifier on the nested type. However, nonnested types (such as the SportsCar) can only be defined with the public or internal modifiers. Therefore, the following class definition is illegal:
// Error! Nonnested types cannot be marked private! private class SportsCar {}
Now that you have seen the access modifiers at work, you are ready to formally investigate the first pillar of OOP.